package util

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/spf13/viper"
)

func ContainsString(slice []string, val string) bool {
	for _, item := range slice {
		if item == val {
			return true
		}
	}
	return false
}

// Encode 将消息编码
func Encode(message string) ([]byte, error) {
	// 读取消息的长度，转换成int32类型（占4个字节）
	var length = int32(len(message))
	var pkg = new(bytes.Buffer)
	// 写入消息头
	err := binary.Write(pkg, binary.LittleEndian, length)
	if err != nil {
		return nil, err
	}
	// 写入消息实体
	err = binary.Write(pkg, binary.LittleEndian, []byte(message))
	if err != nil {
		return nil, err
	}
	return pkg.Bytes(), nil
}

// Decode 解码消息
func Decode(reader *bufio.Reader) (string, error) {
	// 读取消息的长度
	lengthByte, _ := reader.Peek(4) // 读取前4个字节的数据
	lengthBuff := bytes.NewBuffer(lengthByte)
	var length int32
	err := binary.Read(lengthBuff, binary.LittleEndian, &length)
	if err != nil {
		return "", err
	}
	// Buffered返回缓冲中现有的可读取的字节数。
	if int32(reader.Buffered()) < length+4 {
		return "", err
	}

	// 读取真正的消息数据
	pack := make([]byte, int(4+length))
	_, err = reader.Read(pack)
	if err != nil {
		return "", err
	}
	return string(pack[4:]), nil
}

func PrintArr(arr *[5]int) {
	arr[0] = 10
	for _, v := range arr {
		fmt.Println(v)
	}
}

func SumArr(a [10]int) int {
	sum := 0
	for _, v := range a {
		sum += v
	}
	return sum
}

func GetArrAndValue(a [5]int, target int) [][2]int {
	var res [][2]int
	for i := 0; i < len(a); i++ {
		for j := i + 1; j < len(a); j++ {
			if a[i]+a[j] == target {
				fmt.Printf("(%d,%d)\n", i, j)
				// res[len(res)] = {i, j}
				res = append(res, [2]int{i, j})
			}
		}
	}
	return res
}

func Md5Hash(input string) string {
	md5Hash := md5.New()
	md5Hash.Write([]byte(input))
	return hex.EncodeToString(md5Hash.Sum(nil))
}

func CreateDir(dirName string) {

	err := os.MkdirAll(dirName, 0755)
	if err != nil {
		log.Fatal("创建文件夹失败")
	}
}

func CreateLogDir(path string, fileName string) (*os.File, error) {
	now := time.Now()
	// 使用当前时间获取今天的日期
	today := now.Format("2006-01-02")
	dirName := path + today + "/"
	err := os.MkdirAll(dirName, 0755)
	if err != nil {
		return nil, err
	}
	//设置日志文件
	openFile, openFileErr := os.OpenFile(dirName+fileName+".log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if openFileErr != nil {
		return nil, err
	}

	return openFile, nil
}

func GetInitConfig(configName string, defaultValue string) string {
	viper.SetConfigFile("../common/config.ini")
	viper.ReadInConfig()
	configValue := viper.GetString(configName)
	if configValue == "" {
		return defaultValue
	}
	return configValue
}

func IsProd() bool {
	viper.SetConfigFile("../common/config.ini")
	viper.ReadInConfig()
	configValue := viper.GetString("app.debug")
	if configValue == "false" {
		return true
	}
	return false
}

func ConvertStringToInt32Slice(s string) ([]int32, error) {
	strSlice := strings.Split(s, ",") // 将字符串按逗号分隔成字符串切片

	var intSlice []int32

	for _, str := range strSlice {
		num, err := strconv.Atoi(str) // 将字符串转换为int类型
		if err != nil {
			return nil, err // 返回错误
		}
		intSlice = append(intSlice, int32(num)) // 将int类型转换为int32并添加到切片中
	}

	return intSlice, nil
}

func CountSubfolders(dir string) (int, error) {
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return 0, err
	}

	count := 0
	for _, file := range files {
		if file.IsDir() {
			count++
		}
	}
	return count, nil
}

func GetStartAndEndTimestamps(timeStr string) (int64, int64, error) {
	// 设置时间格式
	layout := "2006-01-02"
	// 获取东八区时区
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		return 0, 0, err
	}

	// 解析时间字符串
	t, err := time.ParseInLocation(layout, timeStr, loc)
	if err != nil {
		println(err.Error())
		return 0, 0, err
	}

	// 获取当天的开始时间
	startOfDay := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, loc)
	// 获取当天的结束时间
	endOfDay := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, loc)

	// 返回开始和结束时间的时间戳
	return startOfDay.Unix(), endOfDay.Unix(), nil
}

func SubtractDay(timeStr string, num int) (string, error) {
	// 定义时间格式
	layout := "2006-01-02 15:04:05"
	// 获取东八区时区
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		return "", err
	}

	// 解析时间字符串
	t, err := time.ParseInLocation(layout, timeStr, loc)
	if err != nil {
		return "", err
	}

	// 减去一天
	t = t.AddDate(0, 0, -num)

	// 格式化为相同的字符串格式
	newTimeStr := t.Format(layout)
	return newTimeStr, nil
}

func GetPublicIP() (string, error) {
	resp, err := http.Get("http://ifconfig.me")
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func GetValueInt(a interface{}) (int, error) {
	switch v := a.(type) {
	case int:
		return v, nil
	case int32:
		return int(v), nil
	case string:
		intValue, err := strconv.Atoi(v)
		if err != nil {
			return 0, err
		}
		return intValue, err
	case int64:
		return int(v), nil
	case float64:
		return int(v), nil
	default:
		return 0, nil
	}
}

func GetValueFloat64(a interface{}) (float64, error) {
	switch v := a.(type) {
	case float64:
		return v, nil
	case int32:
		return float64(v), nil
	case string:
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return 0.0, err
		}
		return f, err
	case int64:
		return float64(v), nil
	default:
		return 0.0, nil
	}
}

func GetValueString(a interface{}) (string, error) {
	switch v := a.(type) {
	case float64:
		str := strconv.FormatFloat(v, 'f', 6, 64)
		return str, nil
	case int32:
		str := strconv.Itoa(int(v))
		return str, nil
	case string:
		return v, nil
	case int64:
		str := strconv.FormatInt(v, 10)
		return str, nil
	case int:
		str := strconv.Itoa(v)
		return str, nil
	default:
		return "", nil
	}
}

func GetValueTime(a interface{}) (time.Time, error) {
	switch v := a.(type) {
	case time.Time:
		return v, nil
	case string:
		return time.Parse("2006-01-02 15:04:05", v)
	case int64:
		return time.Unix(v, 0), nil
	default:
		return time.Now(), nil
	}
}

// ExcelSerialToTime 将Excel日期序列号转换为Go的time.Time类型
func ExcelSerialToTime(serial float64) time.Time {
	// Excel日期系统的起始点
	baseDate := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
	// 修正Excel日期系统的一个小错误，它错误地认为1900年是闰年
	if serial > 59 {
		serial--
	}
	// 提取整数部分作为天数
	days := int(serial)
	// 提取小数部分作为一天中的时间比例
	fraction := serial - float64(days)
	// 计算总秒数
	totalSeconds := int(fraction*24*60*60) + 1
	// 在基础日期上加上天数和秒数
	return baseDate.AddDate(0, 0, days-1).Add(time.Duration(totalSeconds) * time.Second)
}

// IsToday 用于判断传入的时间是否是今天
func IsToday(t time.Time) bool {
	// 获取当前时间
	now := time.Now()
	// 获取当前时间的年、月、日
	nowYear, nowMonth, nowDay := now.Date()
	// 获取待判断时间的年、月、日
	tYear, tMonth, tDay := t.Date()
	// 比较年、月、日是否都相同
	return nowYear == tYear && nowMonth == tMonth && nowDay == tDay
}

// 定义包含数字和大写字母的字符集
const randomUpperCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

// 生成指定长度的随机字符串
func GenerateRandomString(length int) string {
	// 初始化随机数种子，避免每次运行生成相同的随机数
	rand.Seed(int64(time.Now().UnixNano()))
	// 创建一个长度为 length 的字节切片，用于存储随机字符
	b := make([]byte, length)
	for i := range b {
		// 从字符集中随机选取一个字符
		b[i] = randomUpperCharset[rand.Intn(len(randomUpperCharset))]
	}
	// 将字节切片转换为字符串并返回
	return string(b)
}

// 去除 HTML 标签的函数
func RemoveHTMLTags(input string) string {
	// 定义匹配 HTML 标签的正则表达式
	re := regexp.MustCompile(`<[^>]*>`)
	// 将匹配到的 HTML 标签替换为空字符串
	return re.ReplaceAllString(input, "")
}

func GetBeforeString(str string, division string) string {
	index := strings.Index(str, division)
	var result string
	if index != -1 {
		// 如果找到，截取之前的部分
		result = str[:index]
		fmt.Println(result)
	} else {
		// 如果未找到，返回原字符串
		result = str
	}
	return result
}

// 检查 bid 是否是 19 位数字
func CheckBid(bid string) bool {
	// 定义匹配 HTML 标签的正则表达式
	re := regexp.MustCompile(`^\d{19,}$`)
	// 将匹配到的 HTML 标签替换为空字符串
	return re.MatchString(bid)
}

func GetRandNum(min, max int) int {
	rand.Seed(int64(time.Now().UnixNano()))
	return rand.Intn(max-min+1) + min
}
